//
// Created by wlk12 on 2024/3/1.
//

#include <iostream>
#include <vector>
#include <memory>
#include <map>

enum class Msg: uint8_t
{
    Add = 0,
    Update,
    Delete,
};

class Observer
{
public:
    Observer() = default;
    virtual ~Observer() = default;

    virtual void update(Msg msg) = 0;
};

class Manager
{
public:
    void addObserver(Msg msg, const std::shared_ptr<Observer>& observer)
    {
        auto it = map.find(msg);
        if (it == map.end())
        {
            map[msg] = ObserverList{observer};
        }
        else
        {
            auto findResult = std::find(it->second.begin(), it->second.end(), observer);
            if (findResult == it->second.end())
            {
                it->second.emplace_back(observer);
            }
        }
    }

    void removeObserver(Msg msg, const std::shared_ptr<Observer>& observer)
    {
        auto it = map.find(msg);
        if (it != map.end())
        {
            auto& list = it->second;
            auto ob = std::find(list.begin(), list.end(), observer);
            if (ob != list.end())
            {
                list.erase(ob);
            }
        }

    }

    void call(Msg msg)
    {
        auto it = map.find(msg);
        if (it != map.end())
        {
            for (auto& observer : it->second)
            {
                observer->update(msg);
            }
        }
    }

private:
    using ObserverList = std::vector<std::shared_ptr<Observer>>;
    std::map<Msg, ObserverList> map;
};

class ObserverA : public Observer
{
public:
    explicit ObserverA(std::string_view name) : name(name){

    }

    void update(Msg msg) override
    {
        std::cout << (int)msg << ": " << name << ", ObserverA Update." << std::endl;
    }

private:
    std::string name;
};

class ObserverB : public Observer
{
public:
    explicit ObserverB(int id) : id(id){

    }

    void update(Msg msg) override
    {
        std::cout << (int)msg << ": " << id << ", ObserverB Update." << std::endl;
    }

private:
    int id{0};
};

int main()
{
    Manager manager;

    auto a1 = std::make_shared<ObserverA>("A1");
    auto a2 = std::make_shared<ObserverA>("A2");
    manager.addObserver(Msg::Add, a1);
    manager.addObserver(Msg::Delete, a2);

    auto b1 = std::make_shared<ObserverB>(1);
    auto b2 = std::make_shared<ObserverB>(2);
    manager.addObserver(Msg::Add, b1);
    manager.addObserver(Msg::Update,b2);
    manager.addObserver(Msg::Add, a1);

    std::cout << "------Add------" << std::endl;
    manager.call(Msg::Add);
    std::cout << "-----Delete-------" << std::endl;
    manager.call(Msg::Delete);
    std::cout << "-----Update-------" << std::endl;
    manager.call(Msg::Update);

    std::cout << "------------" << std::endl;
    manager.removeObserver(Msg::Add, a1);
    manager.call(Msg::Add);


    return 0;
}